﻿using System.Diagnostics;
using LFSRecord2.Model.Undo;
using LFSRecord2.Model.Replay;
using LFSRecord2.Misc;

namespace LFSRecord2.Model
{
    public class CompLayerPropertyDoubleRD : CompLayerPropertyDouble
    {
        public new double DefaultValue { get; private set; }

        private double _currentValue = 0;
        public new double CurrentValue
        {
            get { return (double)_currentValue; }
            set
            {
                _currentValue = value;
                OnPropertyChanged("CurrentValue");
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        public CompLayerPropertyDoubleRD(CompLayerBase parentLayer, int propertyIndex, string propertyName, double defaultValue, LayerPropertyValueMeaning propertyValueMeaning)
            : base(parentLayer, propertyIndex, propertyName, defaultValue, propertyValueMeaning)
        {
            IsEditable = false;
        }

        public override void HandleNewPropertyBinding(CompLayerPropertyBase prop)
        {
        }

        public override void RemoveCurrentValueListener()
        {
        }

        public override CustomKeyFrame SetKeyAtCurrentTime(int frame)
        {
            return null;
        }

        public override void AddKeyFrame(CustomKeyFrame key)
        {
        }
        public override void AddKeyFrame(CustomKeyFrame key, bool autoBezier)
        {
        }

        public override void DeleteAllKeyframes()
        {
        }

        public override object GetValueAtFrame(int frame)
        {
            // This method (in this class) has really only one use : to interpolate HEADING from compcar data

            // Get a reference to our ReplayPlayerData object and replay time offset
            CompLayerReplayData l = (CompLayerReplayData)ParentLayer;
            ReplayPlayerData pData = l.CurrentReplayPlayerData(frame);
            double replayTime = l.CurrentReplayTimeOffset(frame);

            if (pData == null || pData.FirstMciNode() == null)
                return 0.0d;

            // Find the data packets between which to interpolate
            ReplayDataNode fromNode = pData.FirstMciNode(), toNode = null;

            // Time is before first mci datanode
            if (replayTime < fromNode.ReplayTime)
                return 0.0d;

            int numHeadingRevolves = 0;
            int numHeadingRevolvesPrevious = 0;
            double heading = fromNode.MciInfo.Heading, headingPrevious = 0;
            foreach (ReplayDataNode rNode in pData.DataNodes)
            {
                if (!rNode.IsMciNode)
                    continue;

                headingPrevious = heading;
                heading = rNode.MciInfo.Heading;
                numHeadingRevolvesPrevious = numHeadingRevolves;

                if (heading - 31678 > headingPrevious)
                {
                    numHeadingRevolves--;
                }
                else if (heading + 31678 < headingPrevious)
                {
                    numHeadingRevolves++;
                }

                if (replayTime < rNode.ReplayTime)
                {
                    toNode = rNode;
                    if (fromNode == null)
                        fromNode = rNode;
                    break;
                }
                fromNode = rNode;
            }

            // Hold value? (time is beyond last datanode)
            if (toNode == null)
                return fromNode.MciInfo.Heading / -LfsHelper.LfsDegMult + 180;

            replayTime -= fromNode.ReplayTime;
            double timeInterval = toNode.ReplayTime - fromNode.ReplayTime;

            return CustomDoubleInterpolation.InterpolateLinear(
                fromNode.MciInfo.Heading + numHeadingRevolvesPrevious * 360 * LfsHelper.LfsDegMult,
                toNode.MciInfo.Heading + numHeadingRevolves * 360 * LfsHelper.LfsDegMult,
                replayTime / timeInterval) 
                / -LfsHelper.LfsDegMult + 180;
        }

        public override CustomKeyFrame OnCurrentValueChange()
        {
            return null;
        }

        public override bool SetCurrentValue(int frame)
        {
            double newValue = (double)GetValueAtFrame(frame);
            if (CurrentValue == newValue)
                return false;

            CurrentValue = newValue;
            return true;
        }

        public override PropertyDataBase DataStructure()
        {
            Debug.WriteLine("Creating Double RD Property Datastructure");

            PropertyDoubleData propertyData = new PropertyDoubleData()
            {
                ParentLayerIndex = ParentLayer.LayerIndex,
                PropertyIndex = PropertyIndex,
                IsEditable = IsEditable,
                IsSelected = IsSelected,
                IsAnimated = IsAnimated,
                ValueLock = ValueLock,
                BindingPropertyIndex = BindingPropertyIndex,
                BoundPropertyIgnoreParent = BoundPropertyIgnoreParent,
                NumKeyFrames = KeyFrames.Count,
                KeyFrames = new KeyFrameDataBase[KeyFrames.Count],

                CurrentValue = CurrentValue
            };

            return propertyData;
        }
    }
}
